/*
 *	waveio.c
 *
 *	waveio.lib
 *
 *	Audio Finger Print project
 */

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#include <stdio.h>

#include "waveio.h"

void* WAVEIO_Buffer[WAVEIN_BUFFERS];
volatile int WAVEIO_sw = 0;

enum
{
	WAVEIN_Stopped,
	WAVEIN_Started,
};

static int WAVEIN_status = WAVEIN_Stopped;

static int bufLength = 0;
static HWAVEIN hWaveIn;
static WAVEHDR PCMwh[WAVEIN_BUFFERS];

static void CALLBACK waveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2);

void CALLBACK waveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
{
	if(WIM_DATA == uMsg)
	{
		if(WAVEIN_status == WAVEIN_Started)
		{
			WAVEIN_Record();
		}
	}
}

int WAVEIN_Record()
{
	PCMwh[WAVEIO_sw].lpData			= (char*)WAVEIO_Buffer[WAVEIO_sw];
	PCMwh[WAVEIO_sw].dwBufferLength	= bufLength*sizeof(__int16);

	if (waveInPrepareHeader(hWaveIn, &PCMwh[WAVEIO_sw], sizeof(WAVEHDR)) == MMSYSERR_NOERROR)
	{
		waveInAddBuffer(hWaveIn, &PCMwh[WAVEIO_sw], sizeof(WAVEHDR));
		waveInStart(hWaveIn);

		if(++WAVEIO_sw >= WAVEIN_BUFFERS)
		{
			WAVEIO_sw = 0;
		}

		return WAVEIO_NoError;
	}

	return WAVEIO_UnknownError;
}

int WAVEIN_Stop()
{
	int i;

	WAVEIN_status = WAVEIN_Stopped;

	waveInReset(hWaveIn);

//	waveInStop(hWaveIn);

	for(i = 0; i < WAVEIN_BUFFERS; ++i)
	{ 
		waveInUnprepareHeader(hWaveIn, &PCMwh[i], sizeof(WAVEHDR));
	}

	waveInClose(hWaveIn);

	for(i = 0; i < WAVEIN_BUFFERS; ++i)
	{
		GlobalFree(WAVEIO_Buffer[i]);
	}

	return WAVEIO_NoError;
}

int WAVEIN_Open(const int bufLength0)
{
	WAVEFORMATEX format;
	int i;
#if 1
    int num;
    WAVEINCAPS wic;
#endif

	format.cbSize = 0;
	format.wFormatTag = 1; // wave.AudioFormat;
	format.nChannels = 1; // wave.NumChannels;
	format.wBitsPerSample = 16; // wave.BitsPerSample;
	format.nSamplesPerSec = 8000; // wave.SampleRate;
	format.nBlockAlign = 2; //wave.BlockAlign;
	format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;

	bufLength = bufLength0;
	WAVEIO_sw = 0;

	for(i = 0; i < WAVEIN_BUFFERS; ++i)
	{
		if(NULL == (WAVEIO_Buffer[i] = GlobalAlloc(GPTR,bufLength*sizeof(__int16))))
		{
			return WAVEIO_NoMemory;
		}
	}

#if 1
    num = waveInGetNumDevs();
    for(i = 0; i < num; ++i)
    {
        if(MMSYSERR_NOERROR == waveInGetDevCaps(i, &wic, sizeof(wic)))
        {
            printf("wave device %d: %s\n",i,wic.szPname);
        }
    }
    printf("Select wave device ");
    num = getchar()-'0';
    printf("Selected wave device %d\n", num);

	if(MMSYSERR_NOERROR == waveInOpen(&hWaveIn, num, &format, (DWORD_PTR)waveInProc, 0, CALLBACK_FUNCTION|WAVE_FORMAT_DIRECT))
#else
	if(MMSYSERR_NOERROR == waveInOpen(&hWaveIn, WAVE_MAPPER, &format, (DWORD_PTR)waveInProc, 0, CALLBACK_FUNCTION|WAVE_FORMAT_DIRECT))
#endif
	{
		WAVEIN_status = WAVEIN_Started;
		return WAVEIO_NoError;
	}
	else
	{
		return WAVEIO_UnknownError;
	}
}
